package com.ruoyi.tzai.controller;

import java.util.List;
import java.io.OutputStream;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.tzai.domain.NewsAudio;
import com.ruoyi.tzai.service.INewsAudioService;
import com.ruoyi.tzai.service.IFileUploadService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import com.alibaba.fastjson2.JSON;
import org.dromara.x.file.storage.core.FileInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 音频文件Controller
 * 
 * @author tzai
 * @date 2025-10-27
 */
@Api(tags = "音频文件管理")
@RestController
@RequestMapping("/tzai/audio")
public class NewsAudioController extends BaseController
{
    private static final Logger log = LoggerFactory.getLogger(NewsAudioController.class);
    
    @Autowired
    private INewsAudioService newsAudioService;
    
    @Autowired
    private IFileUploadService fileUploadService;

    /**
     * 查询音频文件列表
     */
    @ApiOperation("查询音频文件列表")
    @PreAuthorize("@ss.hasPermi('tzai:audio:list')")
    @GetMapping("/list")
    public TableDataInfo list(NewsAudio newsAudio)
    {
        startPage();
        List<NewsAudio> list = newsAudioService.selectNewsAudioList(newsAudio);
        return getDataTable(list);
    }

    /**
     * 导出音频文件列表
     */
    @ApiOperation("导出音频文件列表")
    @PreAuthorize("@ss.hasPermi('tzai:audio:export')")
    @Log(title = "音频文件", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, NewsAudio newsAudio)
    {
        List<NewsAudio> list = newsAudioService.selectNewsAudioList(newsAudio);
        ExcelUtil<NewsAudio> util = new ExcelUtil<NewsAudio>(NewsAudio.class);
        util.exportExcel(response, list, "音频文件数据");
    }

    /**
     * 获取音频文件详细信息
     */
    @ApiOperation("获取音频文件详细信息")
    @PreAuthorize("@ss.hasPermi('tzai:audio:query')")
    @GetMapping(value = "/{audioId}")
    public AjaxResult getInfo(@PathVariable("audioId") Long audioId)
    {
        return success(newsAudioService.selectNewsAudioByAudioId(audioId));
    }

    /**
     * 根据文章ID和语言获取音频文件（含时间戳）
     * 返回的 audioUrl 为阿里云OSS签名URL（有效期60分钟）
     */
    @ApiOperation("根据文章ID和语言获取音频文件（含时间戳）")
    @GetMapping(value = "/article/{articleId}")
    public AjaxResult getByArticleId(@PathVariable("articleId") Long articleId, 
                                      @RequestParam(required = false, defaultValue = "cn") String language)
    {
        try {
            NewsAudio audio = newsAudioService.selectNewsAudioByArticleIdAndLanguage(articleId, language);
            
            if (audio != null && audio.getFileMetadata() != null && !audio.getFileMetadata().isEmpty()) {
                // 解析 FileInfo
                FileInfo fileInfo = JSON.parseObject(audio.getFileMetadata(), FileInfo.class);
                
                // 生成签名URL（有效期60分钟）
                String signedUrl = fileUploadService.generateSignedUrl(fileInfo, 60);
                
                // 设置签名URL到audioUrl字段
                audio.setAudioUrl(signedUrl);
                
                log.info("为音频 {} 生成签名URL成功", audio.getAudioId());
            }
            
            return success(audio);
        } catch (Exception e) {
            log.error("获取音频信息失败: articleId={}, language={}", articleId, language, e);
            return error("获取音频信息失败");
        }
    }

    /**
     * 新增音频文件
     */
    @ApiOperation("新增音频文件")
    @PreAuthorize("@ss.hasPermi('tzai:audio:add')")
    @Log(title = "音频文件", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody NewsAudio newsAudio)
    {
        return toAjax(newsAudioService.insertNewsAudio(newsAudio));
    }

    /**
     * 修改音频文件
     */
    @ApiOperation("修改音频文件")
    @PreAuthorize("@ss.hasPermi('tzai:audio:edit')")
    @Log(title = "音频文件", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody NewsAudio newsAudio)
    {
        return toAjax(newsAudioService.updateNewsAudio(newsAudio));
    }

    /**
     * 删除音频文件
     */
    @ApiOperation("删除音频文件")
    @PreAuthorize("@ss.hasPermi('tzai:audio:remove')")
    @Log(title = "音频文件", businessType = BusinessType.DELETE)
	@DeleteMapping("/{audioIds}")
    public AjaxResult remove(@PathVariable Long[] audioIds)
    {
        return toAjax(newsAudioService.deleteNewsAudioByAudioIds(audioIds));
    }
    
    /**
     * 在线播放音频文件（重定向到阿里云OSS签名URL）
     * 使用302重定向到OSS，支持流式播放和Range请求
     * 支持 URL 参数 token 认证（用于 Web 音频播放器，JwtAuthenticationTokenFilter 会自动处理）
     */
    @ApiOperation("在线播放音频文件")
    @GetMapping("/play/{audioId}")
    public void play(@PathVariable("audioId") Long audioId, HttpServletResponse response)
    {
        try {
            log.info("播放音频文件（重定向模式）: {}", audioId);
            
            // 1. 查询音频记录
            NewsAudio audio = newsAudioService.selectNewsAudioByAudioId(audioId);
            if (audio == null) {
                log.error("音频记录不存在: {}", audioId);
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                return;
            }
            
            // 2. 解析 FileInfo
            if (audio.getFileMetadata() == null || audio.getFileMetadata().isEmpty()) {
                log.error("音频文件元数据为空: {}", audioId);
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return;
            }
            
            FileInfo fileInfo = JSON.parseObject(audio.getFileMetadata(), FileInfo.class);
            log.info("解析FileInfo成功: {}", fileInfo.getFilename());
            
            // 3. 生成签名URL（有效期60分钟）
            String signedUrl = fileUploadService.generateSignedUrl(fileInfo, 60);
            
            // 4. 302重定向到OSS签名URL
            response.sendRedirect(signedUrl);
            
            log.info("音频文件重定向成功: {} -> {}", audioId, signedUrl);
            
        } catch (Exception e) {
            log.error("播放音频文件失败: " + audioId, e);
            try {
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            } catch (Exception ex) {
                // ignore
            }
        }
    }
    
    /**
     * 下载音频文件
     * 使用 x-file-storage 下载文件
     */
    @ApiOperation("下载音频文件")
    @GetMapping("/download/{audioId}")
    public void download(@PathVariable("audioId") Long audioId, HttpServletResponse response)
    {
        try {
            log.info("下载音频文件: {}", audioId);
            
            // 1. 查询音频记录
            NewsAudio audio = newsAudioService.selectNewsAudioByAudioId(audioId);
            if (audio == null) {
                log.error("音频记录不存在: {}", audioId);
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                return;
            }
            
            // 2. 解析 FileInfo
            if (audio.getFileMetadata() == null || audio.getFileMetadata().isEmpty()) {
                log.error("音频文件元数据为空: {}", audioId);
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return;
            }
            
            FileInfo fileInfo = JSON.parseObject(audio.getFileMetadata(), FileInfo.class);
            log.info("解析FileInfo成功: {}", fileInfo.getFilename());
            
            // 3. 使用 x-file-storage 下载文件
            byte[] fileBytes = fileUploadService.downloadFile(fileInfo);
            if (fileBytes == null || fileBytes.length == 0) {
                log.error("文件下载失败: {}", audioId);
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return;
            }
            
            // 4. 设置响应头（下载模式）
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileInfo.getOriginalFilename() + "\"");
            response.setHeader("Content-Length", String.valueOf(fileBytes.length));
            
            // 5. 写入响应流
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(fileBytes);
            outputStream.flush();
            
            log.info("音频文件下载成功: {} ({}字节)", audioId, fileBytes.length);
            
        } catch (Exception e) {
            log.error("下载音频文件失败: " + audioId, e);
            try {
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            } catch (Exception ex) {
                // ignore
            }
        }
    }
}

